﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using WinForms = System.Windows.Forms;

namespace ArgusLib.Controls
{
	/// <summary>
	/// A TextBox which is capable of showing an instruction Text.
	/// Directly derives from <see cref="WinForms.TextBox"/>.
	/// </summary>
	public class TextBox : WinForms.TextBox
	{
		private WinForms.Label lInstruction;
		private WinForms.ToolTip toolTip;

		/// <summary>
		/// Gets or sets a value indicating whether the instruction text shoud be shown.
		/// The default is false/>.
		/// </summary>
		public bool ShowInstructionText
		{
			get { return this.lInstruction.Visible; }
			set { this.lInstruction.Visible = value; }
		}
		/// <summary>
		/// Gets or sets the instruction text.
		/// The default is null/>.
		/// </summary>
		[System.ComponentModel.Localizable(true)]
		public string InstructionText
		{
			get { return this.lInstruction.Text; }
			set
			{
				this.lInstruction.Text = value;
				this.toolTip.RemoveAll();
				if (string.IsNullOrEmpty(this.lInstruction.Text) == false)
					this.toolTip.SetToolTip(this, this.lInstruction.Text);
			}
		}
		/// <summary>
		/// Gets or sets the <see cref="FontStyle"/> used to display the <see cref="TextBox.InstructionText"/>.
		/// The default is <see cref="FontStyle.Italic"/>.
		/// </summary>
		public FontStyle InstructionFontStyle
		{
			get { return this.lInstruction.Font.Style; }
			set { this.lInstruction.Font = new Font(this.Font, value); }
		}
		/// <summary>
		/// Gets or sets the <see cref="Color"/> used to display the <see cref="TextBox.InstructionText"/>.
		/// The default is <see cref="Color.White"/>.
		/// </summary>
		public Color InstructionColor
		{
			get { return this.lInstruction.ForeColor; }
			set { this.lInstruction.ForeColor = value; }
		}
		/// <summary>
		/// Gets or sets the <see cref="ContentAlignment"/> used to display the <see cref="TextBox.InstructionText"/>.
		/// The default is <see cref="ContentAlignment.MiddleLeft"/>.
		/// </summary>
		public ContentAlignment InstructionTextAlign
		{
			get { return this.lInstruction.TextAlign; }
			set { this.lInstruction.TextAlign = value; }
		}

		public IEnumerable<CharSet> AllowedChars { get; set; }

		/// <summary>
		/// Creates an instance of <see cref="TextBox"/>.
		/// </summary>
		public TextBox()
			: base()
		{
			this.BackColor = Color.Black;
			this.ForeColor = Color.White;

			if (ArgusLib.Environment.Runtime == Runtime.Mono)
				base.ForeColor = Color.Black;

			this.toolTip = new WinForms.ToolTip();
			this.lInstruction = new WinForms.Label();
			this.lInstruction.AutoSize = false;
			this.lInstruction.AutoEllipsis = true;
			this.lInstruction.Dock = WinForms.DockStyle.Fill;

			this.lInstruction.Click += lInstruction_Click;

			this.InstructionText = null;
			this.InstructionFontStyle = FontStyle.Italic;
			this.InstructionColor = this.ForeColor;
			this.InstructionTextAlign = ContentAlignment.MiddleLeft;
			this.ShowInstructionText = false;

			this.AllowedChars = null;

			this.Controls.Add(this.lInstruction);
		}

		void lInstruction_Click(object sender, EventArgs e)
		{
			this.Focus();
		}

		/// <summary>
		/// See <see cref="TextBox.OnFontChanged"/>.
		/// </summary>
		protected override void OnFontChanged(EventArgs e)
		{
			this.lInstruction.Font = new System.Drawing.Font(this.Font, this.InstructionFontStyle);
			base.OnFontChanged(e);
		}

		/// <summary>
		/// See <see cref="TextBox.OnGotFocus"/>.
		/// </summary>
		protected override void OnGotFocus(EventArgs e)
		{
			if (this.ReadOnly == false || string.IsNullOrEmpty(this.Text) == false)
				this.lInstruction.Visible = false;
			base.OnGotFocus(e);
		}

		/// <summary>
		/// See <see cref="TextBox.OnLostFocus"/>.
		/// </summary>
		protected override void OnLostFocus(EventArgs e)
		{
			if (string.IsNullOrEmpty(this.Text) == true)
				this.lInstruction.Visible = true;
			base.OnLostFocus(e);
		}

		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				if (ArgusLib.Environment.Runtime == Runtime.Mono)
					return;
				base.BackColor = value;
			}
		}

		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				if (ArgusLib.Environment.Runtime == Runtime.Mono)
					return;
				base.ForeColor = value;
			}
		}

		public override string Text
		{
			get { return base.Text; }
			set
			{
				if (this.Focused == false)
				{
					this.lInstruction.Visible = string.IsNullOrEmpty(value);
				}
				base.Text = value;
			}
		}

		//protected override void OnKeyDown(WinForms.KeyEventArgs e)
		//{
		//	if (e.Modifiers == WinForms.Keys.Control)
		//	{
		//		if (e.KeyCode == WinForms.Keys.A)
		//		{
		//			this.SelectAll();
		//		}
		//		else if (e.KeyCode == WinForms.Keys.C)
		//		{
		//			WinForms.Clipboard.SetText(this.SelectedText);
		//		}
		//		else if (e.KeyCode == WinForms.Keys.X)
		//		{
		//			WinForms.Clipboard.SetText(this.SelectedText);
		//			int start = this.SelectionStart;
		//			this.Text = this.Text.Remove(start, this.SelectionLength);
		//			this.SelectionStart = start;
		//		}
		//		else if (e.KeyCode == WinForms.Keys.V)
		//		{
		//			string copyText = this.AllowedChars.RemoveUnallowedChars(WinForms.Clipboard.GetText());
		//			int start = this.SelectionStart;
		//			this.Text = this.Text.Remove(start, this.SelectionLength).Insert(start, copyText);
		//			this.SelectionStart = start + copyText.Length;
		//		}
		//	}
		//	base.OnKeyDown(e);
		//}

		protected override void OnKeyPress(WinForms.KeyPressEventArgs e)
		{
			if (char.IsControl(e.KeyChar) == false)
			{
				e.Handled = !this.AllowedChars.Check(e.KeyChar);
			}
			base.OnKeyPress(e);
		}

		protected override void OnTextChanged(EventArgs e)
		{
			if (this.AllowedChars.ContainsUnallowedChars(this.Text) == true)
			{
				int start = this.SelectionStart;
				this.Text = this.AllowedChars.RemoveUnallowedChars(this.Text);
				this.SelectionStart = start;
			}
			else
			{
				base.OnTextChanged(e);
			}
		}

		public void Insert(string text)
		{
			StringBuilder sb = new StringBuilder(this.Text);
			sb.Remove(this.SelectionStart, this.SelectionLength);
			sb.Insert(this.SelectionStart, text);
			int i = this.SelectionStart + text.Length;
			this.Text = sb.ToString();
			this.SelectionStart = i;
		}

	}
}
